#include <mythtv/mythcontext.h>
#include <mythtv/lcddevice.h>

#include <qdir.h>
#include <qurl.h>

#include "AudioPlayer.h"
#include "streaminput.h"
#include "constants.h"
#include "playbackbox.h"

static AudioPlayerThread* m_AudioPlayerThread;

void AudioPlayer::Play()
{
   printf( "AudioPlayer::Play %d, IsPlaying %d\n", CurrentIndex, m_IsPlaying );
   if( !m_IsPlaying )
   {
      SelectionInfo info = m_PlayList.at( CurrentIndex );
printf( "Play %s\n", info.Path.ascii() );
      PlayFile( info.Path );
   }
}

void AudioPlayer::Suspend()
{
   printf( "AudioPlayer::Suspend\n" );
   pause();
}

void AudioPlayer::Resume()
{
   printf( "AudioPlayer::Resume\n" );
   pause();
}

void AudioPlayer::Stop()
{
   printf( "AudioPlayer::Stop\n" );
   stopAll();
}

bool AudioPlayer::Next()
{
   printf( "AudioPlayer::Next\n" );
   CurrentIndex++;
   return Goto( CurrentIndex );
}

bool AudioPlayer::Previous()
{
   printf( "AudioPlayer::Previous\n" );
   CurrentIndex--;
   return Goto( CurrentIndex );
}

bool AudioPlayer::Goto( int index )
{
   bool rc = false;

   printf( "Goto %d, count %d\n", index, (int)m_PlayList.count() );
   if( index >= 0 && index < (int)m_PlayList.count() )
   {
      CurrentIndex = index;
      rc = true;
   }

   return rc;
}

AudioPlayer::AudioPlayer( QValueVector<SelectionInfo>& playList ) :
   m_PlayList( playList )
{
   RootPath = gContext->GetSetting("MythAudio.Store");
   RootPath = QDir::cleanDirPath( RootPath );
   if( !RootPath.endsWith("/") )
   {
      RootPath += "/";
   }

   Active = true;
   m_IsPlaying = false;
   outputBufferSize = 256;
   m_Input = 0;
   m_Output = 0;
   m_Decoder = 0;
   CurrentIndex = 0;

   m_AudioPlayerThread = new AudioPlayerThread( this );
   m_AudioPlayerThread->start();
}

void AudioPlayer::SetHandler( EventInterface* handler )
{
   Handler = handler;
}

void AudioPlayer::ClearHandler()
{
   Mutex.lock();
   Handler = 0;
   Mutex.unlock();
}

void AudioPlayer::run()
{
   //PlayFile( "Albums/Amethystium/Aphelion/01 - Shadow to Light.wma" );
   while( Active )
   {
      m_Wait.wait();
      printf( "AudioPlayer wake\n" );
   }
}

void SetPlayList( QValueVector<SelectionInfo> )
{
}

void AudioPlayer::customEvent( QCustomEvent* event )
{
   QString statusString;
   QString time_string;
   DecoderEvent*  decoderEvent;
   OutputEvent*   outputEvent;

   switch ( (int)event->type() )
   {
   case OutputEvent::Playing:
      printf( "OutputEvent::Playing\n" );
      break;

   case OutputEvent::Buffering:
      printf( "OutputEvent::Buffering\n" );
      break;

   case OutputEvent::Paused:
      printf( "OutputEvent::Paused\n" );
      break;

   case OutputEvent::Info:
      outputEvent = (OutputEvent*)event;
      Mutex.lock();
      if( Handler )
      {
         Handler->AudioPlayer_Progress( outputEvent->elapsedSeconds(), 1000 );
      }
      Mutex.unlock();

//      int eh, em, es, rs, ts;
//      CurrentTime = rs = ts = outputEvent->elapsedSeconds();
//
//      eh = CurrentTime / 3600;
//      em = (CurrentTime / 60) % 60;
//      es = CurrentTime % 60;
//
//      int maxh = maxTime / 3600;
//      int maxm = (maxTime / 60) % 60;
//      int maxs = maxTime % 60;
//
//      if( maxTime <= 0 )
//      {
//         if( eh > 0 )
//         {
//            time_string.sprintf("%d:%02d:%02d", eh, em, es);
//         }
//         else
//         {
//            time_string.sprintf("%02d:%02d", em, es);
//         }
//      }
//      else
//      {
//         if( maxh > 0 )
//         {
//            time_string.sprintf("%d:%02d:%02d / %02d:%02d:%02d", eh, em,
//                                es, maxh, maxm, maxs);
//         }
//         else
//         {
//            time_string.sprintf("%02d:%02d / %02d:%02d", em, es, maxm,
//                                maxs);
//         }
//      }
//
//      if( curMeta )
//      {
//         if( class LCD *lcd = LCD::Get() )
//         {
//            float percent_heard = maxTime<=0?0.0:((float)rs /
//                                                  (float)curMeta->Length()) * 1000.0;
//
//            QString lcd_time_string = time_string;
//
//            // if the string is longer than the LCD width, remove all spaces
//            if( time_string.length() > lcd->getLCDWidth() )
//            {
//               lcd_time_string.remove(' ');
//            }
//
//            lcd->setMusicProgress(lcd_time_string, percent_heard);
//         }
//      }
      break;

   case OutputEvent::Error:
      printf( "OutputEvent::Error\n" );
      statusString = tr("Output error.");

      outputEvent = (OutputEvent*)event;

      cerr << statusString << " " << *outputEvent->errorMessage() << endl;
      MythPopupBox::showOkPopup(gContext->GetMainWindow(),
                                statusString,
                                QString("MythMusic has encountered the following error:\n%1")
                                .arg(*outputEvent->errorMessage()));
      stopAll();

      break;
   case DecoderEvent::Stopped:
      printf( "DecoderEvent::Stopped\n" );
      break;
   case DecoderEvent::Finished:
      printf( "DecoderEvent::Finished\n" );
      DecoderStop();
      m_IsPlaying = false;

      if( Next() )
      {
         Play();
      }
      else
      {
         stopAll();
      }
      break;

   case DecoderEvent::Error:
      printf( "DecoderEvent::Error\n" );
      stopAll();
      QApplication::sendPostedEvents();

      statusString = tr("Decoder error.");

      decoderEvent = (DecoderEvent*)event;

      cerr << statusString << " " << *decoderEvent->errorMessage() << endl;
      break;
   }
}

void AudioPlayer::PlayFile( const QString& path )
{
   QString playfile;

   if( m_IsPlaying )
   {
      printf( "Stopping...\n" );
      PlaybackStop();
      printf( "done\n" );
   }

   playfile = RootPath+path;

   QUrl sourceurl(playfile);
   QString sourcename(playfile);

   if( !m_Output )
   {
      printf( "Opening device...\n" );
      openOutputDevice();
      printf( "done\n" );
   }

   if( m_Output->GetPause() )
   {
      printf( "Pause?...\n" );
      pause();
      printf( "done\n" );
      return;
   }

   if( !sourceurl.isLocalFile() )
   {
      printf( "streaminput...\n" );
      StreamInput streaminput(sourceurl);
      printf( "done\n" );
      printf( "streaminput.setup...\n" );
      streaminput.setup();
      printf( "done\n" );
      printf( "streaminput.socket...\n" );
      m_Input = streaminput.socket();
      printf( "done\n" );
   }
   else
   {
      m_Input = new QFile(playfile);
   }

   if( m_Decoder && !m_Decoder->factory()->supports(sourcename) )
   {
      m_Decoder = 0;
   }

   if( !m_Decoder )
   {
      printf( "1\n" );
      m_Decoder = Decoder::create(sourcename, m_Input, m_Output);

      if( !m_Decoder )
      {
         printf("mythmusic: unsupported fileformat\n");
         stopAll();
         return;
      }

      m_Decoder->setBlockSize(globalBlockSize);
      m_Decoder->addListener(this);
   }
   else
   {
      printf( "2\n" );
      m_Decoder->setInput(m_Input);
      m_Decoder->setFilename(sourcename);
      m_Decoder->setOutput(m_Output);
   }

   currentTime = 0;

   if( m_Decoder->initialize() )
   {
      if( m_Output )
      {
         m_Output->Reset();
      }

      m_Decoder->start();

      m_IsPlaying = true;
   }
   else
   {
      printf( "m_Decoder->initialize failed\n" );
   }
}

void AudioPlayer::openOutputDevice(void)
{
   QString adevice;

   if( gContext->GetSetting("MythAudio.Device") == "default" )
   {
      adevice = gContext->GetSetting("AudioOutputDevice");
   }
   else
   {
      adevice = gContext->GetSetting("MythAudio.Device");
   }

   // TODO: Error checking that device is opened correctly!
   m_Output = AudioOutput::OpenAudio(adevice, "default", 16, 2, 44100,
                                     AUDIOOUTPUT_MUSIC, true,
                                     false /* AC3/DTS pass through */);
   m_Output->setBufferSize(outputBufferSize * 1024);
   m_Output->SetBlocking(false);
   m_Output->addListener(this);
   //m_Output->addListener(mainvisual);
   //m_Output->addVisual(mainvisual);
}

void AudioPlayer::PlaybackStop(void)
{
   DecoderStop();

   if( m_Output )
   {
      delete m_Output;
      m_Output = 0;
   }

   delete m_Input;
   m_Input = 0;

   QString time_string;
   int maxh = maxTime / 3600;
   int maxm = (maxTime / 60) % 60;
   int maxs = maxm % 60;
   if( maxh > 0 )
   {
      time_string.sprintf("%d:%02d:%02d", maxh, maxm, maxs);
   }
   else
   {
      time_string.sprintf("%02d:%02d", maxm, maxs);
   }

//   if( time_text )
//   {
//      time_text->SetText(time_string);
//   }
//   if( info_text )
//   {
//      info_text->SetText("");
//   }

   m_IsPlaying = false;
}

void AudioPlayer::stopAll()
{
   if( class LCD *lcd = LCD::Get() )
   {
      lcd->switchToTime();
   }

   PlaybackStop();

   if( m_Decoder )
   {
      m_Decoder->removeListener(this);
      m_Decoder = 0;
   }
}

void AudioPlayer::DecoderStop(void)
{
   if( m_Decoder && m_Decoder->running() )
   {
      m_Decoder->lock();
      m_Decoder->stop();
      m_Decoder->unlock();
   }

   if( m_Decoder )
   {
      m_Decoder->lock();
      m_Decoder->cond()->wakeAll();
      m_Decoder->unlock();
   }

   if( m_Decoder )
   {
      m_Decoder->wait();
   }
}

void AudioPlayer::pause()
{
   if( m_Output )
   {
      m_IsPlaying = !m_IsPlaying;
      m_Output->Pause( !m_IsPlaying ); //Note pause doesn't take effet instantly
   }
   // wake up threads
   if( m_Decoder )
   {
      m_Decoder->lock();
      m_Decoder->cond()->wakeAll();
      m_Decoder->unlock();
   }
}

void AudioPlayer::SeekForward()
{
//   int nextTime = currentTime + 5;
//   if( nextTime > maxTime )
//   {
//      nextTime = maxTime;
//   }
//   Seek(nextTime);
}

void AudioPlayer::SeekBack()
{
//   int nextTime = currentTime - 5;
//   if( nextTime < 0 )
//   {
//      nextTime = 0;
//   }
//   Seek(nextTime);
}

void AudioPlayer::Seek( int pos )
{
   if( m_Output )
   {
      m_Output->Reset();
      m_Output->SetTimecode(pos*1000);

      if( m_Decoder && m_Decoder->running() )
      {
         m_Decoder->lock();
         m_Decoder->seek(pos);

         m_Decoder->unlock();
      }
   }
}


